package cloudeval.spec.metrics

import cn.edu.neu.vmmigeval.cloud.entity.DataCenter
import cn.edu.neu.vmmigeval.cloud.entity.DataCenterBroker
import cn.edu.neu.vmmigeval.cloud.entity.Host
import cn.edu.neu.vmmigeval.evaluation.Measure

/**
 * The violation times of Service Level Agreement.
 *
 * @author yfwz100
 */
class SLA {

    private static class V implements Measure {

        private double value;

        private double limit
        private Closure<Boolean> operator
        private Closure<Double> current
        private String name

        protected V(String name, double value, Closure<Boolean> operator, Closure<Double> current) {
            this.limit = value
            this.operator = operator
            this.current = current
            this.name = name
        }

        @Override
        void process(int clock, DataCenterBroker dcb, DataCenter dc) {
            value += dc.hosts.sum { Host host ->
                if (operator(current(host))) {
                    1
                } else {
                    0
                }
            } / dc.hosts.size()
        }

        @Override
        double getValue() {
            return value
        }

        @Override
        String getName() {
            return name
        }

        @Override
        String toString() {
            return "SLA: ${getValue()}"
        }
    }

    private static class I {

        private Closure<Double> current
        private String name

        I(String name, Closure<Double> current) {
            this.current = current
            this.name = name
        }

        V leftShift(double v1) {
            new V(name, v1, { double v2 ->
                v2 < v1
            }, current)
        }

        V rightShift(double v1) {
            new V(name, v1, { double v2 ->
                v2 > v1
            }, current)
        }
    }

    static I CPU = new I("SLAV of CPU", { Host host -> host.currentCpu / host.totalCpu })
    static I RAM = new I("SLAV of RAM", { Host host -> host.currentRam / host.totalRam })
    static I Disk = new I("SLAV of Disk", { Host host -> host.currentDisk / host.totalDisk })
    static I BW = new I("SLAV of Bandwidth", { Host host -> host.currentBw / host.totalBw })

}
